package com.clear.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.clear.subject.common.entity.PageResult;
import com.clear.subject.common.enums.IsDeletedFlagEnum;
import com.clear.subject.common.enums.SubjectLikedStatusEnum;
import com.clear.subject.common.util.LoginUtil;
import com.clear.subject.domain.convert.SubjectLikedConverter;
import com.clear.subject.domain.entity.SubjectLikedBO;
import com.clear.subject.domain.entity.SubjectLikedMessage;
import com.clear.subject.domain.redis.RedisUtil;
import com.clear.subject.domain.service.SubjectLikedDomainService;
import com.clear.subject.infra.basic.entity.SubjectInfo;
import com.clear.subject.infra.basic.entity.SubjectLiked;
import com.clear.subject.infra.basic.service.SubjectInfoService;
import com.clear.subject.infra.basic.service.SubjectLikedService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Service
@Slf4j
public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService {

    @Resource
    private SubjectLikedService subjectLikedService;

    @Resource
    private SubjectInfoService subjectInfoService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private RabbitTemplate rabbitTemplate;

    // 题目点赞key
    private static final String SUBJECT_LIKED_KEY = "subject.liked";
    // 题目点赞数
    private static final String SUBJECT_LIKED_COUNT_KEY = "subject.liked.count";

    private static final String SUBJECT_LIKED_DETAIL_KEY = "subject.liked.detail";

    // exchange
    private static final String EXCHANGE_NAME = "jc.club.direct";
    // routingKey
    private static final String ROUTING_KEY = "liked.success";


    /**
     * 题目点赞 或 取消点赞
     *
     * @param subjectLikedBO
     * @return
     */
    @Override
    public void add(SubjectLikedBO subjectLikedBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectLikedDomainServiceImpl.add.bo:{}", JSON.toJSONString(subjectLikedBO));
        }
        Long subjectId = subjectLikedBO.getSubjectId();
        String likeUserId = subjectLikedBO.getLikeUserId();
        // 构建file：subjectId:userId
        String hashKey = buildSubjectLikedKey(subjectId.toString(), likeUserId);
        // 获取value：点赞状态
        Integer status = subjectLikedBO.getStatus();

        redisUtil.putHash(SUBJECT_LIKED_KEY, hashKey, status);

        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + likeUserId;
        String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;
        if (SubjectLikedStatusEnum.LIKED.getCode() == status) {
            // 点赞
            redisUtil.increment(countKey, 1);
            redisUtil.set(detailKey, "1");
        } else {
            // 未点赞 取消点赞
            Integer count = redisUtil.getInt(countKey);
            if (Objects.isNull(count) || count <= 0) {
                return;
            }
            redisUtil.increment(countKey, -1);
            redisUtil.del(detailKey);
        }
    }

    /**
     * 题目点赞 或 取消点赞
     *
     * @param subjectLikedBO
     * @return
     */
    @Override
    public void add2(SubjectLikedBO subjectLikedBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectLikedDomainServiceImpl.add2.bo:{}", JSON.toJSONString(subjectLikedBO));
        }
        Long subjectId = subjectLikedBO.getSubjectId();
        String likeUserId = subjectLikedBO.getLikeUserId();
        Integer status = subjectLikedBO.getStatus();

        SubjectLikedMessage subjectLikedMessage = new SubjectLikedMessage();
        subjectLikedMessage.setSubjectId(subjectId);
        subjectLikedMessage.setLikeUserId(likeUserId);
        subjectLikedMessage.setStatus(status);
        // 发送消息到mq
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING_KEY, JSON.toJSONString(subjectLikedMessage));

        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + likeUserId;
        String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;
        if (SubjectLikedStatusEnum.LIKED.getCode() == status) {
            // 点赞
            redisUtil.increment(countKey, 1);
            redisUtil.set(detailKey, "1");
        } else {
            // 未点赞 取消点赞
            Integer count = redisUtil.getInt(countKey);
            if (Objects.isNull(count) || count <= 0) {
                return;
            }
            redisUtil.increment(countKey, -1);
            redisUtil.del(detailKey);
        }
    }


    /**
     * 获取当前题目是否被该用户点赞过
     *
     * @param subjectId 题目id
     * @param userId    用户id
     * @return 返回是否被点赞过
     */
    @Override
    public Boolean isLiked(String subjectId, String userId) {
        log.info("SubjectLikedDomainServiceImpl.isLiked.params subjectId:{}, userId:{}", subjectId, userId);
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;

        boolean exists = redisUtil.exists(detailKey);

        return exists;
    }

    /**
     * 获取题目点赞数量
     *
     * @param subjectId 题目id
     * @return
     */
    @Override
    public Long getLikedCount(String subjectId) {
        log.info("SubjectLikedDomainServiceImpl.getLikedCount.subjectId:{}", subjectId);
        String countKey = SUBJECT_LIKED_COUNT_KEY + "." + subjectId;

        Integer count = redisUtil.getInt(countKey);
        if (Objects.isNull(count) || count <= 0) {
            return 0L;
        }
        return (long) count;
    }

    /**
     * 同步点赞数据到数据库
     * <br> subject.liked subjectId:userId value(点赞状态)
     */
    @Override
    public void syncLiked() {
        // 获取点赞数据并删除
        Map<Object, Object> subjectLikedMap = redisUtil.getHashAndDelete(SUBJECT_LIKED_KEY);
        if (log.isInfoEnabled()) {
            log.info("SubjectLikedDomainServiceImpl.syncLiked.subjectLikedMap:{}", JSON.toJSONString(subjectLikedMap));
        }
        if (MapUtils.isEmpty(subjectLikedMap)) {
            // 点赞数据为空，返回
            return;
        }
        // 批量同步到数据库
        List<SubjectLiked> subjectLikedList = new LinkedList<>();
        subjectLikedMap.forEach((k, v) -> {
            SubjectLiked subjectLiked = new SubjectLiked();
            String[] keyArr = k.toString().split(":");
            String subjectId = keyArr[0];
            String likeUserId = keyArr[1];

            subjectLiked.setSubjectId(Long.valueOf(subjectId));
            subjectLiked.setLikeUserId(likeUserId);
            subjectLiked.setStatus(Integer.valueOf(v.toString()));
            subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETE.getCode());

            subjectLikedList.add(subjectLiked);
        });
        subjectLikedService.batchInsertOrUpdate(subjectLikedList);

    }

    /**
     * 根据mq消息 同步点赞数据
     */
    @Override
    public void syncLikedByMessage(SubjectLikedBO subjectLikedBO) {
        List<SubjectLiked> subjectLikedList = new LinkedList<>();
        SubjectLiked subjectLiked = new SubjectLiked();
        subjectLiked.setSubjectId(subjectLikedBO.getSubjectId());
        subjectLiked.setLikeUserId(subjectLikedBO.getLikeUserId());
        subjectLiked.setStatus(subjectLikedBO.getStatus());
        subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETE.getCode());

        subjectLikedList.add(subjectLiked);

        subjectLikedService.batchInsertOrUpdate(subjectLikedList);
    }

    /**
     * 查询我的点赞列表
     *
     * @param subjectLikedBO
     * @return
     */
    @Override
    public PageResult<SubjectLikedBO> getSubjectLikedPage(SubjectLikedBO subjectLikedBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectLikedDomainServiceImpl.getSubjectLikedPage.bo:{}", JSON.toJSONString(subjectLikedBO));
        }
        PageResult<SubjectLikedBO> pageResult = new PageResult<>();
        // 在入参BO中拿值并写在返回的BO中
        pageResult.setPageNo(subjectLikedBO.getPageNo());
        pageResult.setPageSize(subjectLikedBO.getPageSize());
        int start = (subjectLikedBO.getPageNo() - 1) * subjectLikedBO.getPageSize();

        SubjectLiked subjectLiked = SubjectLikedConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
        subjectLiked.setLikeUserId(LoginUtil.getLoginId());

        int count = subjectLikedService.countByCondition(subjectLiked);
        if (count == 0) {
            return pageResult;
        }
        List<SubjectLiked> subjectLikedList = subjectLikedService.queryPage(subjectLiked, start,
                subjectLikedBO.getPageSize());

        List<SubjectLikedBO> subjectLikedBOList = SubjectLikedConverter.INSTANCE.convertEntityListToBOList(subjectLikedList);
        // 遍历将题目名称set进去
        subjectLikedBOList.forEach(likedBO -> {
            SubjectInfo subjectInfo = subjectInfoService.queryById(likedBO.getSubjectId());
            likedBO.setSubjectName(subjectInfo.getSubjectName());
        });
        pageResult.setRecords(subjectLikedBOList);
        pageResult.setTotal(count);

        return pageResult;
    }


    private String buildSubjectLikedKey(String subjectId, String userId) {
        return new StringBuffer().append(subjectId).append(":").append(userId).toString();
    }
}
